package com.mhh.selary.backend.api.impl.api;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mhh.sdk.beans.enums.http.HttpMethodEnum;
import com.mhh.sdk.beans.exception.BusinessException;
import com.mhh.sdk.utils.beans.BeanCopyUtils;
import com.mhh.sdk.utils.structure.DataUtils;
import com.mhh.selary.backend.api.api.ISelaryApiHttpService;
import com.mhh.selary.backend.dao.api.api.ISelaryApiHttpDao;
import com.mhh.selary.backend.dao.api.api.ISelaryApiHttpParamDao;
import com.mhh.selary.backend.dao.entity.api.SelaryApiHttpEntity;
import com.mhh.selary.backend.dao.entity.api.SelaryApiHttpParamEntity;
import com.mhh.selary.backend.domain.api.ApiHttpDomain;
import com.mhh.selary.backend.dto.IdDTO;
import com.mhh.selary.backend.dto.api.ApiHttpCopyDTO;
import com.mhh.selary.backend.dto.api.ApiHttpInfo;
import com.mhh.selary.backend.dto.api.ApiHttpMoveDTO;
import com.mhh.selary.backend.dto.api.ApiHttpRunDTO;
import com.mhh.selary.backend.dto.api.ApiHttpRunResultDTO;
import com.mhh.selary.backend.dto.api.ApiHttpSaveDTO;
import com.mhh.selary.backend.enums.BizErrorEnum;
import com.mhh.selary.backend.enums.MediaTypeEnum;
import com.mhh.selary.backend.enums.ParamTypeEnum;
import com.mhh.selary.backend.enums.ProtocolEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * SelaryApiHttpServiceImpl
 *
 * @author 人工智能
 * @date 2020-09-14 15:43:19
 */
@Slf4j
@Service
public class SelaryApiHttpServiceImpl implements ISelaryApiHttpService {

    @Autowired
    private ISelaryApiHttpDao selaryApiHttpDao;

    @Autowired
    private ISelaryApiHttpParamDao selaryApiHttpParamDao;

    @Override
    public List<ApiHttpInfo> listByGroup(Long groupId) {
        LambdaQueryWrapper<SelaryApiHttpEntity> queryWrapper = new LambdaQueryWrapper<SelaryApiHttpEntity>().eq(SelaryApiHttpEntity::getGroupId, groupId);
        List<SelaryApiHttpEntity> apiHttpEntityList = selaryApiHttpDao.list(queryWrapper);
        return apiHttpEntityList.stream().map(this::transfer).collect(Collectors.toList());
    }

    @Override
    public void saveApiHttp(ApiHttpSaveDTO dto) {
        SelaryApiHttpEntity httpEntity = this.fillApiHttp(dto);
        selaryApiHttpDao.saveOrUpdate(httpEntity);

        LambdaQueryWrapper<SelaryApiHttpParamEntity> queryWrapper = new LambdaQueryWrapper<SelaryApiHttpParamEntity>().eq(SelaryApiHttpParamEntity::getApiId, httpEntity.getId());
        selaryApiHttpParamDao.remove(queryWrapper);

        List<SelaryApiHttpParamEntity> paramEntityList = this.apiHttpParam(httpEntity.getId(), dto);
        selaryApiHttpParamDao.saveBatch(paramEntityList);
    }

    private SelaryApiHttpEntity fillApiHttp(ApiHttpSaveDTO dto) {
        SelaryApiHttpEntity httpEntity = new SelaryApiHttpEntity();
        httpEntity.setId(dto.getId());
        httpEntity.setGroupId(dto.getGroupId());
        httpEntity.setApiName(dto.getApiName());
        httpEntity.setProtocol(dto.getProtocol());
        httpEntity.setMethod(dto.getMethod());
        httpEntity.setApiUrl(dto.getApiUrl());
        httpEntity.setRequestType(dto.getDataType());
        if (MediaTypeEnum.isBody(dto.getDataType())) {
            String requestBody = dto.getRequestBody();
            if (MediaTypeEnum.APPLICATION_JSON.getType().equals(dto.getDataType())) {
                requestBody = DataUtils.prettyJson(requestBody);
            }
            httpEntity.setRequestBody(requestBody);
        } else {
            httpEntity.setRequestBody("");
        }
        return httpEntity;
    }

    private List<SelaryApiHttpParamEntity> apiHttpParam(Long apiId, ApiHttpSaveDTO dto) {
        List<SelaryApiHttpParamEntity> paramEntityList = Lists.newArrayList();
        paramEntityList.addAll(this.saveApiHttpParam(apiId, ParamTypeEnum.HEADER.getType(), dto.getHeadMap()));
        if (MediaTypeEnum.isParam(dto.getDataType())) {
            paramEntityList.addAll(this.saveApiHttpParam(apiId, ParamTypeEnum.PARAMS.getType(), dto.getParamMap()));
        }
        return paramEntityList;
    }

    @Override
    public void delApiHttp(@RequestBody IdDTO dto) {
        selaryApiHttpDao.removeById(dto.getId());
    }

    @Override
    public ApiHttpSaveDTO detail(Long apiId) {
        SelaryApiHttpEntity httpEntity = selaryApiHttpDao.getById(apiId);
        ApiHttpSaveDTO saveDTO = new ApiHttpSaveDTO();
        if (httpEntity == null) {
            return saveDTO;
        }
        saveDTO.setId(apiId);
        saveDTO.setGroupId(httpEntity.getGroupId());
        saveDTO.setApiName(httpEntity.getApiName());
        saveDTO.setProtocol(httpEntity.getProtocol());
        saveDTO.setMethod(httpEntity.getMethod());
        saveDTO.setApiUrl(httpEntity.getApiUrl());
        saveDTO.setDataType(httpEntity.getRequestType());
        saveDTO.setRequestBody(httpEntity.getRequestBody());

        LambdaQueryWrapper<SelaryApiHttpParamEntity> queryWrapper = new LambdaQueryWrapper<SelaryApiHttpParamEntity>().eq(SelaryApiHttpParamEntity::getApiId, apiId);
        List<SelaryApiHttpParamEntity> paramEntityList = selaryApiHttpParamDao.list(queryWrapper);
        if (CollectionUtils.isNotEmpty(paramEntityList)) {
            paramEntityList.forEach(entity -> {
                Map<String, String> paramMap = Maps.newHashMap();
                if (ParamTypeEnum.HEADER.getType().equals(entity.getParamType())) {
                    paramMap = saveDTO.getHeadMap();
                    if (paramMap == null) {
                        paramMap = Maps.newHashMap();
                        saveDTO.setHeadMap(paramMap);
                    }
                } else if (ParamTypeEnum.PARAMS.getType().equals(entity.getParamType())) {
                    paramMap = saveDTO.getParamMap();
                    if (paramMap == null) {
                        paramMap = Maps.newHashMap();
                        saveDTO.setParamMap(paramMap);
                    }
                }
                paramMap.put(entity.getParamKey(), entity.getParamValue());
            });
        }
        return saveDTO;
    }

    @Override
    public void copyApiHttp(ApiHttpCopyDTO dto) {
        SelaryApiHttpEntity httpEntity = selaryApiHttpDao.getById(dto.getId());
        SelaryApiHttpEntity newHttpEntity = BeanCopyUtils.copyObject(httpEntity, SelaryApiHttpEntity.class);
        newHttpEntity.setId(null);
        newHttpEntity.setApiName(dto.getApiName());
        newHttpEntity.setGroupId(dto.getGroupId());
        newHttpEntity.setCreateTime(null);
        selaryApiHttpDao.save(newHttpEntity);

        LambdaQueryWrapper<SelaryApiHttpParamEntity> queryWrapper = new LambdaQueryWrapper<SelaryApiHttpParamEntity>().eq(SelaryApiHttpParamEntity::getApiId, dto.getId());
        List<SelaryApiHttpParamEntity> paramEntityList = selaryApiHttpParamDao.list(queryWrapper);
        List<SelaryApiHttpParamEntity> newParamEntityList = paramEntityList.stream().map(entity -> {
            SelaryApiHttpParamEntity newParamEntity = BeanCopyUtils.copyObject(entity, SelaryApiHttpParamEntity.class);
            newParamEntity.setApiId(newHttpEntity.getId());
            newParamEntity.setCreateTime(null);
            return newParamEntity;
        }).collect(Collectors.toList());
        selaryApiHttpParamDao.saveBatch(newParamEntityList);
    }

    @Override
    public void moveApiHttp(ApiHttpMoveDTO dto) {
        SelaryApiHttpEntity httpEntity = selaryApiHttpDao.getById(dto.getId());
        httpEntity.setGroupId(dto.getGroupId());
        selaryApiHttpDao.updateById(httpEntity);
    }

    private List<SelaryApiHttpParamEntity> saveApiHttpParam(Long apiId, Integer paramType, Map<String, String> paramMap) {
        if (MapUtils.isEmpty(paramMap)) {
            return Collections.emptyList();
        }
        return paramMap.entrySet().stream().map(entry -> {
            SelaryApiHttpParamEntity paramEntity = new SelaryApiHttpParamEntity();
            paramEntity.setApiId(apiId);
            paramEntity.setParamType(paramType);
            paramEntity.setParamKey(entry.getKey());
            paramEntity.setParamValue(entry.getValue());
//            paramEntity.setParamDesc();
            return paramEntity;
        }).collect(Collectors.toList());
    }

    @Override
    public ApiHttpRunResultDTO run(ApiHttpRunDTO dto) {
        SelaryApiHttpEntity httpEntity;
        List<SelaryApiHttpParamEntity> paramEntityList;
        if (dto.getId() != null) {
            httpEntity = selaryApiHttpDao.getById(dto.getId());
            LambdaQueryWrapper<SelaryApiHttpParamEntity> queryWrapper = new LambdaQueryWrapper<SelaryApiHttpParamEntity>().eq(SelaryApiHttpParamEntity::getApiId, dto.getId());
            paramEntityList = selaryApiHttpParamDao.list(queryWrapper);
        } else {
            if (StringUtils.isBlank(dto.getApiUrl())) {
                throw new BusinessException(BizErrorEnum.API_URL_NOT_EMPTY);
            }
            ApiHttpSaveDTO saveDTO = BeanCopyUtils.copyObject(dto, ApiHttpSaveDTO.class);
            httpEntity = this.fillApiHttp(saveDTO);
            paramEntityList = this.apiHttpParam(httpEntity.getId(), saveDTO);
        }
        return ApiHttpDomain.init(dto.getEnvId(), httpEntity, paramEntityList).send();
    }

    private ApiHttpInfo transfer(SelaryApiHttpEntity apiHttpEntity) {
        ApiHttpInfo apiHttpInfo = new ApiHttpInfo();
        apiHttpInfo.setId(apiHttpEntity.getId());
        apiHttpInfo.setApiName(apiHttpEntity.getApiName());
        apiHttpInfo.setGroupId(apiHttpEntity.getGroupId());
        HttpMethodEnum methodEnum = HttpMethodEnum.valueBy(apiHttpEntity.getMethod());
        String url = "";
        if (methodEnum != null) {
            url += methodEnum.getMethod() + " ";
        }
        ProtocolEnum protocolEnum = ProtocolEnum.valueBy(apiHttpEntity.getProtocol());
        if (protocolEnum != null) {
            url += protocolEnum.getProtocol() + "://";
        }
        if (StringUtils.isNotBlank(apiHttpEntity.getApiUrl())) {
            url += apiHttpEntity.getApiUrl();
        }
        apiHttpInfo.setUrl(url);
        MediaTypeEnum mediaTypeEnum = MediaTypeEnum.valueBy(apiHttpEntity.getRequestType());
        if (mediaTypeEnum != null) {
            apiHttpInfo.setDataTypeDesc(mediaTypeEnum.getMedia());
        }
        return apiHttpInfo;
    }

}
